local GameLayer = class("GameLayer", cc.Layer)

function GameLayer:ctor()
    --记录触摸的起始与终值
    self.startPosX = 0
    self.startPosY = 0
    local direction = 0
    self:onTouch(function(event)
        if event.name == "began" and event.x > LeftMargin and event.x < display.width - RightMargin and event.y > BottonMargin and event.y < BottonMargin + RowNum * element_size then
            return self:onTouchBegan(event)
        elseif event.name == "ended" and event.x > LeftMargin and event.x < display.width - RightMargin and event.y > BottonMargin and event.y < BottonMargin + RowNum * element_size then
            self:onTouchEnded(event)
        end
    end, false, true)
end

function GameLayer:onTouchBegan(event)
    self.startPosX = math.ceil((event.x - LeftMargin) / element_size)
    --cclog("%d-%d/%d",event.y,BottonMargin,element_size)
    self.startPosY = math.ceil((event.y - BottonMargin) / element_size)
    --cclog("%d_%d", self.startPosY, self.startPosX)
    return true
end

function GameLayer:onTouchEnded(event)
    self.endPosX = math.ceil((event.x - LeftMargin) / element_size)
    self.endPosY = math.ceil((event.y - BottonMargin) / element_size)
    --cclog("%d_%d", self.endPosY, self.endPosX)
    if (isCanTouch and math.abs(self.endPosY - self.startPosY) + math.abs(self.endPosX - self.startPosX) < 2) then
        self:Exchange()
    end
end

function GameLayer:Exchange()
    local firstSprite = self:getChildByName(string.format("%d_%d", self.startPosY, self.startPosX))
    local lastSprite = self:getChildByName(string.format("%d_%d", self.endPosY, self.endPosX))

    lastSprite:runAction(cc.Sequence:create(
            cc.MoveTo:create(0.5, cc.p(LeftMargin + (self.startPosX - 0.5) * element_size, BottonMargin + (self.startPosY - 0.5) * element_size)))
    )
    firstSprite:runAction(cc.Sequence:create(
            cc.MoveTo:create(0.5, cc.p(LeftMargin + (self.endPosX - 0.5) * element_size, BottonMargin + (self.endPosY - 0.5) * element_size))
    ))

    lastSprite:setName(string.format("%d_%d", self.startPosY, self.startPosX))
    firstSprite:setName(string.format("%d_%d", self.endPosY, self.endPosX))

    local tpType = gameBoard[self.endPosY][self.endPosX].etype
    gameBoard[self.endPosY][self.endPosX].etype = gameBoard[self.startPosY][self.startPosX].etype
    gameBoard[self.startPosY][self.startPosX].etype = tpType

    performWithDelay(self, function()
        if self:hasEliminate() then
            self:findEliminate()
        else
            --若无可变目标 直接进行一个反向交换
            local temp = self.endPosX
            self.endPosX = self.startPosX
            self.startPosX = temp
            temp = self.endPosY
            self.endPosY = self.endPosY
            self.endPosY = temp
            self:ExchangeBack()
        end
    end, 0.5)
end

--本质上与交换逻辑没有区别，仅仅是不进行检测判断
function GameLayer:ExchangeBack()
    local firstSprite = self:getChildByName(string.format("%d_%d", self.startPosY, self.startPosX))
    local lastSprite = self:getChildByName(string.format("%d_%d", self.endPosY, self.endPosX))

    lastSprite:runAction(cc.Sequence:create(
            cc.MoveTo:create(0.5, cc.p(LeftMargin + (self.startPosX - 0.5) * element_size, BottonMargin + (self.startPosY - 0.5) * element_size)))
    )
    firstSprite:runAction(cc.Sequence:create(
            cc.MoveTo:create(0.5, cc.p(LeftMargin + (self.endPosX - 0.5) * element_size, BottonMargin + (self.endPosY - 0.5) * element_size))
    ))

    lastSprite:setName(string.format("%d_%d", self.startPosY, self.startPosX))
    firstSprite:setName(string.format("%d_%d", self.endPosY, self.endPosX))

    local tpType = gameBoard[self.endPosY][self.endPosX].etype
    gameBoard[self.endPosY][self.endPosX].etype = gameBoard[self.startPosY][self.startPosX].etype
    gameBoard[self.startPosY][self.startPosX].etype = tpType
end


function GameLayer:hasEliminate()
    --cclog("开始进行可消除检测")
    for i = 1, RowNum do
        for j = 1, ColNum do
            if gameBoard[i][j].etype ~= ElementEliminateType then
                if i > 1 --横向三连
                        and gameBoard[i - 1][j].etype == gameBoard[i][j].etype
                        and i < RowNum
                        and gameBoard[i + 1][j].etype == gameBoard[i][j].etype then

                    return true
                end

                if j > 1--纵向
                        and gameBoard[i][j - 1].etype == gameBoard[i][j].etype
                        and j < ColNum
                        and gameBoard[i][j + 1].etype == gameBoard[i][j].etype then

                    return true
                end
            end
        end
    end
    return false
end

function GameLayer:findEliminate()
    for i = 1, RowNum do
        for j = 1, ColNum do
            if i > 1 --纵向三连
                    and gameBoard[i - 1][j].etype == gameBoard[i][j].etype
                    and i < RowNum
                    and gameBoard[i + 1][j].etype == gameBoard[i][j].etype then
                if gameBoard[i][j].marked == false and gameBoard[i][j].etype ~= ElementEliminateType then
                    self:setEliminate(gameBoard[i][j].etype, i, j)
                end
            end

            if j > 1 --横向三连
                    and gameBoard[i][j - 1].etype == gameBoard[i][j].etype
                    and j < RowNum
                    and gameBoard[i][j + 1].etype == gameBoard[i][j].etype then
                if gameBoard[i][j].marked == false and gameBoard[i][j].etype ~= ElementEliminateType then
                    self:setEliminate(gameBoard[i][j].etype, i, j)
                end
            end
        end
    end
    self:doEliminate()
end

function GameLayer:setEliminate(etype, i, j)
    --递归边界:不越界、不已被消除、不类型不同
    if i < 1 or i > RowNum or j < 1 or j > ColNum or gameBoard[i][j].marked or gameBoard[i][j].etype ~= etype then
        return
    end
    gameBoard[i][j].marked = true
    --print("需要消除：",i,"_",j)
    self:setEliminate(etype, i - 1, j)
    self:setEliminate(etype, i + 1, j)
    self:setEliminate(etype, i, j - 1)
    self:setEliminate(etype, i, j + 1)
end

function GameLayer:doEliminate()
    for i = 1, RowNum do
        for j = 1, ColNum do
            if gameBoard[i][j].marked then
                gameBoard[i][j].etype = ElementEliminateType
                local sprite = self:getChildByName(string.format("%d_%d", i, j))
                sprite:setTexture(EliminateStarImg)
                sprite:setContentSize(element_size, element_size)

                sprite:stopAllActions()
                --延时消除特效
                sprite:runAction(cc.Sequence:create(
                        cc.ScaleTo:create(0.5, 0.01),
                        cc.DelayTime:create(0.5),
                        cc.RemoveSelf:create()
                ))
                --cclog("已更改：",i,j)
            end
        end
    end

    performWithDelay(self, function()
        self:drop()
    end, 0.5)
end

function GameLayer:drop()
    isCanTouch = false
    for j = 1, ColNum do

        --从左下角开始，拿每一列的剩余精灵
        local sprites = {}
        local spritesPosition = {}
        local count = 1
        for i = 1, RowNum do

            if gameBoard[i][j].etype ~= ElementEliminateType then
                local sprite = self:getChildByName(string.format("%d_%d", i, j))
                sprites[count] = sprite
                spritesPosition[count] = gameBoard[i][j].etype
                count = count + 1
            end
        end
        count = count - 1
        --cclog(count)


        --每列进行下降
        local ept = 1

        for idx = 1, count do
            gameBoard[idx][j].etype = spritesPosition[idx]
            gameBoard[idx][j].marked = false

            local newPosition = (cc.p(LeftMargin + (j - 0.5) * element_size, BottonMargin + (idx - 0.5) * element_size))
            sprites[idx]:setName(string.format("%d_%d", ept, j))
            sprites[idx]:runAction(cc.Sequence:create(
                    cc.MoveTo:create(0.5, newPosition)
            ))

            ept = ept + 1
        end
        while ept < RowNum + 1 do
            gameBoard[ept][j].etype = ElementEliminateType
            gameBoard[ept][j].marked = true
            ept = ept + 1
        end

    end

    self:runAction(cc.Sequence:create(
            cc.DelayTime:create(0.6),
            cc.CallFunc:create(function()
                self:fillVacant()
            end),
    --cc.DelayTime:create(1.2),
            cc.CallFunc:create(function()
                if self:hasEliminate() then
                    self:findEliminate()
                end
            end)
    )
    )

    isCanTouch = true
end

function GameLayer:fillVacant()
    --cclog("填补顶层空白")
    for i = 1, RowNum do
        for j = 1, ColNum do
            if gameBoard[i][j].marked == true then
                local randomType = math.random(1, 6)
                gameBoard[i][j].etype = randomType
                gameBoard[i][j].marked = false

                local sprite
                if gameBoard[i][j].etype < 7 then
                    local tp = ELementImgArray[gameBoard[i][j].etype]
                    sprite = cc.Sprite:create(tp)
                else
                    sprite = cc.Sprite:create(EliminateStarImg)
                end
                sprite:setContentSize(element_size, element_size)
                local real_position = (cc.p(LeftMargin + (j - 0.5) * element_size, BottonMargin + (i - 0.5) * element_size))
                sprite:setPosition(real_position)
                sprite:setName(string.format("%d_%d", i, j))
                self:addChild(sprite, GameBoardLevel)
            end
        end
    end
end
return GameLayer
